package com.github.xzb617.client.route.scg.filter;

import com.github.xzb617.client.route.scg.props.RouteProperties;
import com.github.xzb617.client.route.scg.rules.RoutingRule;
import com.github.xzb617.client.route.scg.rules.RoutingRuleChain;
import com.github.xzb617.client.route.scg.rules.impl.HeaderRoutingRule;
import com.github.xzb617.client.route.scg.rules.impl.IpRoutingRule;
import com.github.xzb617.client.route.scg.rules.impl.QueryParamRoutingRule;
import com.github.xzb617.client.route.scg.transfers.ScgHeaderTransfer;
import com.github.xzb617.client.route.scg.utils.WebUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;

@Component
public class RouteFilter implements GlobalFilter, Ordered {

    private final static Logger LOGGER = LoggerFactory.getLogger(RouteFilter.class);
    private final RouteProperties routeProperties;

    public RouteFilter(RouteProperties routeProperties) {
        this.routeProperties = routeProperties;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();

        // 需要往后传递的请求头
        HttpHeaders nextHeaders = new HttpHeaders();

        // 处理请求头参数透传
        ScgHeaderTransfer.matchNeedTransferHeadersAndAddToScgHeader(nextHeaders, request);

        // 自定义规则式路由
        String ipAddr = WebUtil.getClientIpAddr(request);
        RoutingRuleChain routingRuleChain = this.buildChain();
        routingRuleChain.executeMatches(request, nextHeaders, ipAddr, this.routeProperties.getRule(), routingRuleChain);

        // 将现在的request 变成 exchange 对象
        Consumer<HttpHeaders> httpHeaders = httpHeader -> {
            Set<Map.Entry<String, List<String>>> entries = nextHeaders.entrySet();
            for (Map.Entry<String, List<String>> entry : entries) {
                httpHeader.addAll(entry.getKey(), entry.getValue());
            }
        };
        ServerHttpRequest newRequest = exchange.getRequest().mutate().headers(httpHeaders).build();
        ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();
        return chain.filter(newExchange);
    }

    @Override
    public int getOrder() {
        return 10100;
    }

    /**
     * 构建规则链
     */
    private RoutingRuleChain buildChain() {
        List<RoutingRule> routingRules = new ArrayList<>(3);
        routingRules.add(new IpRoutingRule());
        routingRules.add(new HeaderRoutingRule());
        routingRules.add(new QueryParamRoutingRule());
        return new RoutingRuleChain(routingRules);
    }

    /**
     * 设置向后传递的header
     *
     * @param chain
     * @param exchange
     */
    protected Mono<Void> chainFilterAndSetHeaders(GatewayFilterChain chain, ServerWebExchange exchange, HttpHeaders headers) {
        // 添加header
        Consumer<HttpHeaders> httpHeaders = httpHeader -> {
            httpHeader = headers;
        };

        ServerHttpRequest newRequest = exchange.getRequest().mutate().headers(httpHeaders).build();
        ServerWebExchange build = exchange.mutate().request(newRequest).build();
        // 将现在的request 变成 exchange对象
        return chain.filter(build);
    }

}
